package com.lord.rowcopy.util;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.time.DurationFormatUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * 日期工具类
 * 
 * @author Lord
 * @date 2013-9-25
 * 
 */
@Slf4j
public class DateUtil {

    public static final String PATTERN_TIME = "HH:mm:ss";

    /** 缺省日期格式 */
    public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";

    public static final String PATTERN_SEQUENCE = "yyyyMMddHHmmssSSS";

    /** 缺省时间格式 */
    public static final String DEFAULT_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    /** 缺省时间格式 带毫秒 */
    public static final String pattern_ymd_hms_s = "yyyy-MM-dd HH:mm:ss:SSS";

    public static String format(ZonedDateTime dateTime) {
        return format(dateTime, DEFAULT_TIME_PATTERN);
    }

    public static String format(ZonedDateTime dateTime, String pattern) {
        if (dateTime == null) {
            return null;
        }

        return dateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    public static String now() {
        return format(ZonedDateTime.now());
    }

    /**
     * 将日期转换成yyyy-MM-dd格式的字符串
     * 
     * @author zhanglun
     * @param date
     *            要转换成字符串的日期
     * @return 转换后的yyyy-MM-dd格式字符串，如果date为空，返回null
     */
    public static String date2Str(Date date) {
        return date2Str(date, null, null);
    }

    /**
     * 将日期毫秒数串转换成yyyy-MM-dd格式的字符串
     * 
     * @author zhanglun
     * @param date
     *            要转换成字符串的日期毫秒数串
     * @return 转换后的yyyy-MM-dd格式字符串
     */
    public static String date2Str(long date) {
        return date2Str(new Date(date), null, null);
    }

    /**
     * 转换日期为指定格式字符串
     * 
     * @author zhanglun
     * @param date
     *            要转换成字符串的日期
     * @param pattern
     *            要转换的日期格式，如：yyyy-MM-dd、yyyy/MM/dd、yyyy-MM-dd
     *            HH:mm:ss等，如果为空，则默认转换为yyyy-MM-dd格式
     * @return 转换后的指定格式字符串，如果date为空，返回null
     */
    public static String date2Str(Date date, String pattern) {
        return date2Str(date, pattern, null);
    }

    /**
     * 转换日期毫秒数串为指定格式字符串
     * 
     * @author zhanglun
     * @param date
     *            要转换成字符串的日期毫秒数串
     * @param pattern
     *            要转换的日期格式，如：yyyy-MM-dd、yyyy/MM/dd、yyyy-MM-dd
     *            HH:mm:ss等，如果为空，则默认转换为yyyy-MM-dd格式
     * @return 转换后的指定格式字符串
     */
    public static String date2Str(long date, String pattern) {
        return date2Str(new Date(date), pattern, null);
    }

    /**
     * 将日期转换成yyyy-MM-dd格式的字符串
     * 
     * @author zhanglun
     * @param date
     *            要转换成字符串的日期
     * @param timeZone
     *            时区，如果为空，则默认获取本地机器时区
     * @return 按时区转换后的yyyy-MM-dd格式字符串，如果date为空，返回null
     */
    public static String date2Str(Date date, TimeZone timeZone) {
        return date2Str(date, null, timeZone);
    }

    /**
     * 将日期毫秒数串转换成yyyy-MM-dd格式的字符串
     * 
     * @author zhanglun
     * @param date
     *            要转换成字符串的日期毫秒数串
     * @param timeZone
     *            时区，如果为空，则默认获取本地机器时区
     * @return 按时区转换后的yyyy-MM-dd格式字符串
     */
    public static String date2Str(long date, TimeZone timeZone) {
        return date2Str(new Date(date), null, timeZone);
    }

    /**
     * 转换日期为指定格式字符串
     * 
     * @author zhanglun
     * @param date
     *            要转换成字符串的日期
     * @param pattern
     *            要转换的日期格式，如：yyyy-MM-dd、yyyy/MM/dd、yyyy-MM-dd
     *            HH:mm:ss等，如果为空，则默认转换为yyyy-MM-dd格式
     * @param timeZone
     *            时区，如果为空，则默认获取本地机器时区
     * @return 按时区转换后的指定格式字符串，如果date为空，返回null
     */
    public static String date2Str(Date date, String pattern, TimeZone timeZone) {
        if (date == null) {
            return null;
        }
        if (pattern == null || "".equals(pattern.trim())) {
            pattern = DEFAULT_TIME_PATTERN;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern.trim());
        if (timeZone != null) {
            sdf.setTimeZone(timeZone);
        }
        return sdf.format(date);
    }

    /**
     * 转换日期毫秒数串为指定格式字符串
     * 
     * @author zhanglun
     * @param date
     *            要转换成字符串的日期毫秒数串
     * @param pattern
     *            要转换的日期格式，如：yyyy-MM-dd、yyyy/MM/dd、yyyy-MM-dd
     *            HH:mm:ss等，如果为空，则默认转换为yyyy-MM-dd格式
     * @param timeZone
     *            时区，如果为空，则默认获取本地机器时区
     * @return 按时区转换后的指定格式字符串
     */
    public static String date2Str(long date, String pattern, TimeZone timeZone) {
        return date2Str(new Date(date), pattern, timeZone);
    }

    /**
     * 转换常用日期格式的字符串为日期类型
     * 
     * @author zhanglun
     * @param str
     *            要转换成日期类型的常用格式字符串 支持
     *            yyMMdd、yyyyMMdd、yyyy-MM-dd、yyyy/MM/dd、yyyy.MM.dd
     *            yyyyMMddHHmm、yyyyMMddHHmmss、yyyyMMddHHmmssSSS、yyyy-MM-dd
     *            HH:mm:ss yyyy/MM/dd HH:mm:ss、yyyy-MM-dd
     *            HH:mm:ss.SSS、yyyy/MM/dd HH:mm:ss.SSS等格式
     * @return 转换后的日期类型，如果str为空，返回null
     */
    public static Date str2Date(String str) {
        return str2Date(str, null, null);
    }

    /**
     * 转换常用日期格式的字符串为日期类型
     * 
     * @author zhanglun
     * @param str
     *            要转换成日期类型的常用格式字符串
     * @param timeZone
     *            时区，如果为空，则默认获取本地机器时区
     * @return 按时区转换后的日期类型，如果str为空，返回null
     */
    public static Date str2Date(String str, TimeZone timeZone) {
        return str2Date(str, null, timeZone);
    }

    /**
     * 转换指定日期格式的字符串为日期类型
     * 
     * @author zhanglun
     * @param str
     *            要转换成日期类型的字符串
     * @param pattern
     *            参数str所属的日期格式，如果为空，则自动根据str匹配常用的日期格式
     * @return 转换后的日期类型，如果str为空，返回null
     */
    public static Date str2Date(String str, String pattern) {
        return str2Date(str, pattern, null);
    }

    /**
     * 转换指定日期格式的字符串为日期类型
     * 
     * @author zhanglun
     * @param str
     *            要转换成日期类型的常用格式字符串
     * @param pattern
     *            参数str所属的日期格式，如果为空，则自动根据str匹配常用的日期格式
     * @param timeZone
     *            时区，如果为空，则默认获取本地机器时区
     * @return 按时区转换后的日期类型，如果str为空，返回null
     */
    public static Date str2Date(String str, String pattern, TimeZone timeZone) {
        if (str == null || "".equals(str.trim())) {
            return null;
        }
        str = str.trim();
        if (pattern == null || "".equals(pattern.trim())) {
            if (str.length() == 6) {
                pattern = "yyMMdd";
            } else if (str.length() == 8) {
                pattern = "yyyyMMdd";
            } else if (str.length() == 10) {
                if (str.indexOf("-") != -1) {
                    pattern = "yyyy-MM-dd";
                } else if (str.indexOf("/") != -1) {
                    pattern = "yyyy/MM/dd";
                } else if (str.indexOf(".") != -1) {
                    pattern = "yyyy.MM.dd";
                }
            } else if (str.length() == 12) {
                pattern = "yyyyMMddHHmm";
            } else if (str.length() == 14) {
                pattern = "yyyyMMddHHmmss";
            } else if (str.length() == 17) {
                pattern = "yyyyMMddHHmmssSSS";
            } else if (str.length() == 19) {
                if (str.indexOf(":") != -1) {
                    if (str.indexOf("-") != -1) {
                        pattern = "yyyy-MM-dd HH:mm:ss";
                    } else if (str.indexOf("/") != -1) {
                        pattern = "yyyy/MM/dd HH:mm:ss";
                    }
                }
            } else if (str.length() == 23) {
                if (str.indexOf(":") != -1 && str.indexOf(".") != -1) {
                    if (str.indexOf("-") != -1) {
                        pattern = "yyyy-MM-dd HH:mm:ss.SSS";
                    } else if (str.indexOf("/") != -1) {
                        pattern = "yyyy/MM/dd HH:mm:ss.SSS";
                    }
                }
            }
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern.trim());
        if (timeZone != null) {
            sdf.setTimeZone(timeZone);
        }
        try {
            return sdf.parse(str);
        } catch (ParseException e) {
            throw new RuntimeException("日期格式错误");
        }
    }

    /**
     * 格式化日期为指定格式的日期
     * 
     * @author zhanglun
     * @param date
     *            要格式化的日期
     * @param pattern
     *            格式化后的日期格式，如果为空，则默认格式化为yyyy-MM-dd HH:mm:ss格式
     * @return 格式化后的日期，如果date为空，返回null
     */
    public static Date date2Date(Date date, String pattern) {
        return date2Date(date, pattern, null);
    }

    /**
     * 格式化日期为指定格式的日期
     * 
     * @author zhanglun
     * @param date
     *            要格式化的日期
     * @param pattern
     *            格式化后的日期格式，如果为空，则默认格式化为yyyy-MM-dd HH:mm:ss格式
     * @param timeZone
     *            时区，如果为空，则默认获取本地机器时区
     * @return 按时区格式化后的日期，如果date为空，返回null
     */
    public static Date date2Date(Date date, String pattern, TimeZone timeZone) {
        if (date == null) {
            return null;
        }
        if (pattern == null || "".equals(pattern.trim())) {
            pattern = DEFAULT_TIME_PATTERN;
        }
        return str2Date(date2Str(date, pattern.trim(), timeZone), pattern.trim(), timeZone);
    }

    /**
     * 根据时区ID取得时区，如果非java已知标准名字，则必须为 GMT[+-]hh:mm 格式
     * 
     * @author zhanglun
     * @param id
     *            时区ID
     * @return 时区
     */
    public static TimeZone getTimeZone(String id) {
        if (id == null) {
            return null;
        }
        // 全部时区名字
        List<String> timeZoneIds = Arrays.asList(TimeZone.getAvailableIDs());
        if (timeZoneIds.contains(id)) {
            return TimeZone.getTimeZone(id);
        }
        Pattern p = Pattern.compile("^GMT[+-](0[0-9]|1[01]):([0-5][0-9])$");
        Matcher m = p.matcher("id");
        if (!m.matches()) {
            return null;
        }
        int hh = Integer.parseInt(id.substring(4, 6));
        int mm = Integer.parseInt(id.substring(7));
        int sign = (id.charAt(3) == '-' ? -1 : 1);
        return new SimpleTimeZone((hh * 60 + mm) * 60000 * sign, id);
    }

    /**
     * 获取指定日期一天中最小的开始时间
     * 
     * @author zhanglun
     * @param date
     *            日期
     * @return 如果date为空，返回null 例：2013-06-08 15:34:21 返回 2013-06-08 00:00:00
     */
    public static Date getMinDateInDay(Date date) {
        return date2Date(date, DEFAULT_DATE_PATTERN);
    }

    /**
     * 获取指定日期一天中最大的结束时间
     * 
     * @author zhanglun
     * @param date
     *            日期
     * @return 如果date为空，返回null 例：2013-06-08 15:34:21 返回 2013-06-08 23:59:59
     */
    public static Date getMaxDateInDay(Date date) {
        if (date == null) {
            return null;
        }
        String endStr = date2Str(date);
        endStr += " " + "23:59:59";
        return str2Date(endStr);
    }

    /**
     * 比较两个日期是否是同一天，只考虑年月日，不考虑具体时分秒
     * 
     * @author zhanglun
     * @param date1
     *            要比较的第一个日期
     * @param date2
     *            要比较的第二个日期
     * @return 如果是同一天返回true，否则返回false 例：2013-06-13 15:34:21 与 2013-06-13
     *         08:12:44 返回 true 2013-06-13 15:34:21 与 2013-06-12 15:34:21
     *         返回false
     */
    public static boolean isDayEqual(Date date1, Date date2) {
        return date2Str(date1).equals(date2Str(date2));
    }

    /**
     * 比较两个日期的大小，精确到毫秒数进行比较
     * 
     * @author zhanglun
     * @param date1
     *            要比较的第一个日期
     * @param date2
     *            要比较的第二个日期
     * @return 如果date1 = date2，返回0 如果date1 > date2，返回正数 1 如果date1 < date2，返回负数
     *         -1 例：2013-05-06 08:22:33(date1) 与 2013-05-06 08:22:34(date2) 返回
     *         -1
     */
    public static int compare(Date date1, Date date2) {
        return date1.compareTo(date2);
    }

    /**
     * 比较两个日期格式字符串的大小，两个字符串的格式必须为str2Date方法支持的常用日期格式范围内
     * 
     * @author zhanglun
     * @param date1
     *            要比较的第一个日期格式字符串
     * @param date2
     *            要比较的第二个日期格式字符串
     * @return 如果date1 = date2，返回0 如果date1 > date2，返回正数 1 如果date1 < date2，返回负数
     *         -1 例：2013-05-06 08:22:33(date1) 与 2013-05-06 08:22:32(date2) 返回 1
     */
    public static int compare(String date1, String date2) {
        return str2Date(date1).compareTo(str2Date(date2));
    }

    /**
     * 比较两个日期格式字符串的大小，两个字符串的日期格式必需一致
     * 
     * @author zhanglun
     * @param date1
     *            要比较的第一个日期格式字符串
     * @param date2
     *            要比较的第二个日期格式字符串
     * @param pattern
     *            参数date1和date2所属的日期格式，不能为空
     * @return 如果date1 = date2，返回0 如果date1 > date2，返回正数 1 如果date1 < date2，返回负数
     *         -1 例：2013-05-06 08:22:33(date1) 与 2013-05-06 08:22:33(date2) 返回 0
     */
    public static int compare(String date1, String date2, String pattern) {
        return str2Date(date1, pattern).compareTo(str2Date(date2, pattern));
    }

    /**
     * 返回指定日期某个日历字段的值
     * 
     * @author zhanglun
     * @param date
     *            日期，不能为空
     * @param field
     *            日历字段， 年(1)、月(2)、日(5)、时(11)、分(12)、秒(13)
     * @return 给定日历字段的值 例：get(2013-05-06 08:22:33 , 2) 返回 4
     */
    public static int get(Date date, int field) {
        if (date == null) {
            throw new RuntimeException("日期不能为空");
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(field);
    }

    /**
     * 获取指定日期的前一天
     * 
     * @author zhanglun
     * @param date
     *            日期，不能为空
     * @return 指定日期的前一天 例：2012-05-16，返回2012-05-15 2014-01-01，返回2013-12-31
     */
    public static Date getPrevDay(Date date) {
        return addDay(date, -1);
    }

    /**
     * 获取指定日期的后一天
     * 
     * @author zhanglun
     * @param date
     *            日期，不能为空
     * @return 指定日期的后一天 例：2012-05-16，返回2012-05-17 2013-12-31，返回2014-01-01
     */
    public static Date getNextDay(Date date) {
        return addDay(date, 1);
    }

    /**
     * 得到指定日期的前几天或后几天日期
     * 
     * @author zhanglun
     * @param date
     *            日期，不能为空
     * @param day
     *            参数day<0 代表是前几天，day>0 代表是后几天， day=0返回原日期
     * @return 经过增加或减去后的日期 例：addDay(2012-05-16 , -5) 返回 2012-05-11
     */
    public static Date addDay(Date date, int day) {
        return addDate(date, Calendar.DATE, day);
    }

    /**
     * 得到指定日期的前几月或后几月日期
     * 
     * @author zhanglun
     * @param date
     *            日期，不能为空
     * @param month
     *            参数month<0 代表是前几月，month>0 代表是后几月， month=0返回原日期
     * @return 经过增加或减去后的日期 例：addMonth(2012-05-16 , 3) 返回 2012-08-16
     */
    public static Date addMonth(Date date, int month) {
        return addDate(date, Calendar.MONTH, month);
    }

    /**
     * 增加或减小时间
     * 
     * @author zhanglun
     * @param date
     *            日期，不能为空
     * @param field
     *            日历字段，年(1)、月(2)、日(5)、时(11)、分(12)、秒(13)
     * @param amount
     *            为日历字段添加的日期或时间量，如果为负数，说明是向前减小日期
     * @return 经过增加或减去后的日期
     */
    public static Date addDate(Date date, int field, int amount) {
        if (date == null) {
            return null;
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(field, amount);
        return c.getTime();
    }

    /**
     * 获取日期时间段内的自然日期集合（包含开始和结束日期当天），只精确到天，不考虑时分秒
     * 
     * @author zhanglun
     * @param beginDate
     *            开始日期，不能为空
     * @param endDate
     *            结束日期，不能为空
     * @return 两个时间段内的自然日期集合，包含开始和结束日期当天 例：2012-10-12至2012-10-15
     *         返回[2012-10-12、2012-10-13、2012-10-14、2012-10-15]
     */
    public static List<Date> getBetweenDays(Date beginDate, Date endDate) {
        return getBetweenDays(beginDate, endDate, 0, 0);
    }

    /**
     * 获取日期时间段内的日期集合，只精确到天，不考虑时分秒
     * 
     * @author zhanglun
     * @param beginDate
     *            开始日期，不能为空
     * @param endDate
     *            结束日期，不能为空
     * @param type
     *            需要获取的日期类型。0：自然日，1：工作日（周一至周五），2：周末（周六或周日）
     * @param include
     *            是否包含开始和结束日期当天。0：都包含，1：只包含开始，2：只包含结束，3：都不包含
     * @return 两个时间段内的日期集合 例：getBetweenDays(2012-10-12, 2012-10-15, 0, 2)
     *         返回[2012-10-13、2012-10-14、2012-10-15]
     */
    public static List<Date> getBetweenDays(Date beginDate, Date endDate, int type, int include) {
        if (beginDate == null || endDate == null) {
            return null;
        }
        List<Date> dateList = new ArrayList<Date>();
        Date begin = date2Date(beginDate, DEFAULT_DATE_PATTERN);
        Date end = date2Date(endDate, DEFAULT_DATE_PATTERN);
        long dayCount = getBetweenDayCount(begin, end);
        Calendar c = Calendar.getInstance();
        if (compare(begin, end) <= 0) {
            c.setTime(begin);
        } else {
            c.setTime(end);
        }

        int i = 0;
        if (include == 1) {
            dayCount = dayCount - 1;
        } else if (include == 2) {
            i = 1;
            c.add(Calendar.DATE, 1);
        } else if (include == 3) {
            i = 1;
            c.add(Calendar.DATE, 1);
            dayCount = dayCount - 1;
        }

        for (; i <= dayCount; i++) {
            if (type == 0) {
                dateList.add(c.getTime());
            } else if (type == 1 && isWork(c.getTime())) {
                dateList.add(c.getTime());
            } else if (type == 2 && isWeekEnd(c.getTime())) {
                dateList.add(c.getTime());
            }
            c.add(Calendar.DATE, 1);
        }
        return dateList;
    }

    /**
     * 获取两个日期时间段内的相差自然日天数，不考虑时分秒
     * 
     * @author zhanglun
     * @param beginDate
     *            开始日期，不能为空
     * @param endDate
     *            结束日期，不能为空
     * @return 两个日期时间段内的相差自然日天数 例： 2014-10-28与2014-10-30 返回相差天数为 2
     */
    public static int getBetweenDayCount(Date beginDate, Date endDate) {
        if (beginDate == null || endDate == null) {
            throw new RuntimeException("日期不能为空");
        }
        long count = (date2Date(beginDate, DEFAULT_DATE_PATTERN).getTime()
                - date2Date(endDate, DEFAULT_DATE_PATTERN).getTime()) / (24 * 3600 * 1000);
        return Integer.parseInt(String.valueOf(Math.abs(count)));
    }

    /**
     * 获取两个日期时间段内的相差天数，不考虑时分秒
     * 
     * @author zhanglun
     * @param beginDate
     *            开始日期，不能为空
     * @param endDate
     *            结束日期，不能为空
     * @param type
     *            需要计算的日期类型。0：自然日，1：工作日（周一至周五），2：周末（周六或周日）
     * @return 两个日期时间段内的相差天数
     */
    public static int getBetweenDayCount(Date beginDate, Date endDate, int type) {
        if (beginDate == null || endDate == null) {
            throw new RuntimeException("日期不能为空");
        }
        int count = 0;
        Date begin = date2Date(beginDate, DEFAULT_DATE_PATTERN);
        Date end = date2Date(endDate, DEFAULT_DATE_PATTERN);
        Calendar c = Calendar.getInstance();
        if (compare(begin, end) > 0) {
            Date tmp = begin;
            begin = end;
            end = tmp;
        }
        c.setTime(begin);
        while (!isDayEqual(end, c.getTime())) {
            if (type == 0) {
                count++;
            } else if (type == 1 && isWork(c.getTime())) {
                count++;
            } else if (type == 2 && isWeekEnd(c.getTime())) {
                count++;
            }
            c.add(Calendar.DATE, 1);
        }
        return count;
    }

    /**
     * 获取两个日期时间段内相差的月份数，只考虑年份和月份，不考虑天或时分秒
     * 
     * @author zhanglun
     * @param beginDate
     *            开始日期，不能为空
     * @param endDate
     *            结束日期，不能为空
     * @return 两个日期时间段内相差的月份数 例：2013-05-26 和 2013-06-01返回 1 2013-05-26 和
     *         2012-02-02返回 15
     */
    public static int getBetweenMonthCount(Date beginDate, Date endDate) {
        if (beginDate == null || endDate == null) {
            throw new RuntimeException("日期不能为空");
        }
        Calendar c1 = Calendar.getInstance();
        c1.setTime(date2Date(beginDate, "yyyy-MM"));
        Calendar c2 = Calendar.getInstance();
        c2.setTime(date2Date(endDate, "yyyy-MM"));

        if (c1.after(c2)) {
            Calendar tmp = c1;
            c1 = c2;
            c2 = tmp;
        }
        return (c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR)) * 12 + c2.get(Calendar.MONTH) - c1.get(Calendar.MONTH);
    }

    /**
     * 得到指定日期当前月份可能拥有的最大天数
     * 
     * @author zhanglun
     * @param date
     *            日期，不能为空
     * @return 当前月份可能拥有的最大天数 例：2000-02-21 返回29天 2014-07-11 返回31天
     */
    public static int getMaxDayInMonth(Date date) {
        if (date == null) {
            throw new RuntimeException("日期不能为空");
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.getActualMaximum(Calendar.DATE);
    }

    /**
     * 得到某年某月可能拥有的最大天数
     * 
     * @author zhanglun
     * @param year
     *            年份，必须为4位数字，如：2012
     * @param month
     *            月份，只能为1-12的数字，1代表1月，8代表8月
     * @return 指定年月可能拥有的最大天数
     */
    public static int getMaxDayInMonth(int year, int month) {
        if (String.valueOf(year).length() != 4) {
            throw new RuntimeException("年份格式不正确！");
        }
        if (month > 12 || month < 1) {
            throw new RuntimeException("月份格式不正确！");
        }
        Calendar c = Calendar.getInstance();
        c.clear();
        c.set(Calendar.YEAR, year);
        c.set(Calendar.MONTH, month - 1);
        return c.getActualMaximum(Calendar.DATE);
    }

    /**
     * 得到指定日期是该年中的第几周
     * 
     * @author zhanglun
     * @param date
     *            日期，不能为空
     * @return 是该年中的第几周
     */
    public static int getWeekInYear(Date date) {
        if (date == null) {
            throw new RuntimeException("日期不能为空");
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.WEEK_OF_YEAR);
    }

    /**
     * 获取指定日期是星期几
     * 
     * @author zhanglun
     * @param date
     *            日期，不能为空
     * @return 例：星期一返回 1 ，星期三返回3，星期六返回6，星期日返回 7
     */
    public static int getWeek(Date date) {
        if (date == null) {
            throw new RuntimeException("日期不能为空");
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        int week = c.get(Calendar.DAY_OF_WEEK) - 1;
        if (week == 0) {
            week = 7;
        }
        return week;
    }

    /**
     * 判断输入的年份是否为闰年
     * 
     * @author zhanglun
     * @param year
     *            年份，必须为4位数字，如：2012
     * @return 如果是闰年，返回true，否则返回false
     */
    public static boolean isLeapYear(int year) {
        if (String.valueOf(year).length() != 4) {
            throw new RuntimeException("年份格式不正确！");
        }
        if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
            return true;
        }
        return false;
    }

    /**
     * 判断指定日期是否为该月末的最后一天
     * 
     * @author zhanglun
     * @param date
     *            日期，不能为空
     * @return 如果为月末最后一天，返回true，否则返回false 例：2012-12-31返回true 2012-12-28返回false
     */
    public static boolean isEndDayInMonth(Date date) {
        if (date == null) {
            throw new RuntimeException("日期不能为空");
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        if (c.get(Calendar.DATE) == getMaxDayInMonth(date)) {
            return true;
        }
        return false;
    }

    /**
     * 判断指定日期是否为周末（周六或周日）
     * 
     * @author zhanglun
     * @param date
     *            日期，不能为空
     * @return 如果为周末（周六或周日），返回true，否则返回false
     */
    public static boolean isWeekEnd(Date date) {
        int week = getWeek(date);
        if (week == 6 || week == 7) {
            return true;
        }
        return false;
    }

    /**
     * 判断指定日期是否为工作日（周一至周五）
     * 
     * @author zhanglun
     * @param date
     *            日期，不能为空
     * @return 如果为工作日（周一至周五），返回true，否则返回false
     */
    public static boolean isWork(Date date) {
        return !isWeekEnd(date);
    }

    /**
     * 将出生日期与当前系统日期进行计算，获得年龄（周岁）
     * 
     * @author zhanglun
     * @param birthdayDate
     *            出生日期，不能为空
     * @return 年龄（周岁）
     */
    public static int getAge(Date birthdayDate) {
        return getAge(date2Str(birthdayDate));
    }

    /**
     * 将出生日期与当前系统日期进行计算，获得年龄（周岁）
     * 
     * @author zhanglun
     * @param birthdayDate
     *            出生日期字符串，格式如：1991-05-06
     * @return 年龄（周岁）
     */
    public static int getAge(String birthdayDate) {
        if (birthdayDate == null || birthdayDate == "") {
            throw new RuntimeException("出生日期不能为空");
        }
        // 转换出生日期和当前日期全部为yyyy-MM-dd的格式，且没有时分秒
        Date date1 = date2Date(str2Date(birthdayDate), DEFAULT_DATE_PATTERN);
        Date date2 = date2Date(new Date(), DEFAULT_DATE_PATTERN);
        if (compare(date1, date2) > 0) {
            throw new RuntimeException("出生日期不能大于当前日期");
        }

        Calendar c1 = Calendar.getInstance();
        c1.setTime(date1);
        Calendar c2 = Calendar.getInstance();
        c2.setTime(date2);

        int flag = 0;
        if (c2.get(Calendar.MONTH) < c1.get(Calendar.MONTH)) {
            flag = 1;
        } else if (c2.get(Calendar.MONTH) == c1.get(Calendar.MONTH)) {
            if (c2.get(Calendar.DATE) < c1.get(Calendar.DATE)) {
                flag = 1;
            }
        }

        return c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR) - flag;
    }

    /**
     * 将日期集合按升序排序
     * 
     * @author zhanglun
     * @param dates
     *            要排序的日期集合
     * @return 升序后的日期集合
     */
    public static List<Date> sort(List<Date> dates) {
        return sort(dates, true);
    }

    /**
     * 日期集合排序
     * 
     * @author zhanglun
     * @param dates
     *            要排序的日期集合
     * @param order
     *            如果为true：升序，false：降序
     * @return 排序后的集合
     */
    public static List<Date> sort(List<Date> dates, boolean order) {
        if (dates == null || dates.size() <= 0) {
            return dates;
        }
        Collections.sort(dates);
        if (order == false) {
            List<Date> list = new ArrayList<Date>();
            for (int i = dates.size() - 1; i >= 0; i--) {
                list.add(dates.get(i));
            }
            return list;
        }
        return dates;
    }

    // ================新增方法 by ma.guanghui 2015/8/25================

    /**
     * 主要是给jfinal使用，数据库只认java.sql.*
     * @param date
     * @return
     */
    public static Timestamp getSqlTimestamp(Date date) {
        if (null == date) {
            date = new Date();
        }
        return getSqlTimestamp(date.getTime());
    }

    /**
     * 主要是给jfinal使用，数据库只认java.sql.*
     * @param time
     * @return
     */
    public static Timestamp getSqlTimestamp(long time) {
        return new java.sql.Timestamp(time);
    }

    /**
     * 获取当前时间
     * @return
     */
    public static Date getDate() {
        return new Date();
    }

    /**
     * 获取当前时间的时间戳
     * @return
     */
    public static long getDateByTime() {
        return new Date().getTime();
    }

    /**
     * 格式化
     * @param date
     * @param pattern
     * @return
     */
    public static String format(Date date, String pattern) {
        DateFormat format = new SimpleDateFormat(pattern);
        return format.format(date);
    }

    /**
     * 格式化
     * @param date
     * @param parsePattern
     * @param returnPattern
     * @return
     */
    public static String format(String date, String parsePattern, String returnPattern) {
        return format(parse(date, parsePattern), returnPattern);
    }

    /**
     * 解析
     * @param date
     * @param pattern
     * @return
     */
    public static Date parse(String date, String pattern) {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        try {
            return format.parse(date);
        } catch (ParseException e) {
            log.error("ToolDateTime.parse异常：date值" + date + "，pattern值" + pattern);
            return null;
        }
    }

    /**
     * 解析
     * @param dateStr
     * @return
     */
    public static Date parse(String dateStr) {
        Date date = null;
        try {
            date = DateFormat.getDateTimeInstance().parse(dateStr);
        } catch (ParseException e) {
            log.error("ToolDateTime.parse异常：date值" + date);
            return null;
        }
        return date;
    }

    /**
     * 两个日期的时间差，返回"X天X小时X分X秒"
     * 
     * @param begin
     * @param end
     * @return
     */
    public static String getBetween(Date begin, Date end) {
        long between = (end.getTime() - begin.getTime()) / 1000;// 除以1000是为了转换成秒
        long day = between / (24 * 3600);
        long hour = between % (24 * 3600) / 3600;
        long minute = between % 3600 / 60;
        long second = between % 60 / 60;

        StringBuilder sb = new StringBuilder();
        sb.append(day);
        sb.append("天");
        sb.append(hour);
        sb.append("小时");
        sb.append(minute);
        sb.append("分");
        sb.append(second);
        sb.append("秒");

        return sb.toString();
    }

    /**
     * 返回两个日期之间隔了多少小时
     * 
     * @param date1
     * @param end
     * @return
     */
    public static int getDateHourSpace(Date start, Date end) {
        int hour = (int) ((end.getTime() - start.getTime()) / 3600 / 1000);
        return hour;
    }

    /**
     * 返回两个日期之间隔了多少天
     * 
     * @param date1
     * @param end
     * @return
     */
    public static int getDateDaySpace(Date start, Date end) {
        int day = getDateHourSpace(start, end) / 24;
        return day + 1;
    }

    /**
     * 返回两个日期之间隔了多少月
     * 
     * @param date1
     * @param end
     * @return
     */
    public static int getMonthSpace(Date start, Date end) {
        String formatPeriod = DurationFormatUtils.formatPeriod(start.getTime(), end.getTime(), "y-M-d");
        String[] split = formatPeriod.split("-");
        int month = Integer.parseInt(split[1]);
        return month;
    }

    /**
     * 返回当前日期的天数
     * @param date
     * @return
     */
    public static int getDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.DATE);
    }

    /**
     * 返回当前日期的月数
     * @param date
     * @return
     */
    public static int getMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.MONTH) + 1;
    }

    /**
     * 返回当前日期的年数
     * @param date
     * @return
     */
    public static int getYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.YEAR);
    }

    /**
     * 返回本年任意月份有多少天
     * @param date
     * @return
     */
    public static int getDaysOfMonth(int year, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, 1);
        return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    /**
     * 返回两个日期之间隔了多少月
     * @param date
     * @return
     */
    public static int calDiffMonth(Date startDate, Date endDate) {
        int result = 0;

        int startYear = getYear(startDate);
        int startMonth = getMonth(startDate);
        int startDay = getDay(startDate);
        int endYear = getYear(endDate);
        int endMonth = getMonth(endDate);
        int endDay = getDay(endDate);
        if (startDay > endDay) { // 1月17 大于 2月28
            if (endDay == getDaysOfMonth(getYear(new Date()), 2)) { // 也满足一月
                result = (endYear - startYear) * 12 + endMonth - startMonth;
            } else {
                result = (endYear - startYear) * 12 + endMonth - startMonth - 1;
            }
        } else {
            result = (endYear - startYear) * 12 + endMonth - startMonth;
        }

        return result;
    }

    /**
     * 返回两个日期之间隔了多少年
     * 
     * @param date1
     * @param end
     * @return
     */
    public static int getYearSpace(Date start, Date end) {
        String formatPeriod = DurationFormatUtils.formatPeriod(start.getTime(), end.getTime(), "y-M-d");
        String[] split = formatPeriod.split("-");
        int year = Integer.parseInt(split[0]);
        return year;
    }

    /**
     * 得到某一天是星期几
     * @param strDate 日期字符串
     * @return String 星期几
     */
    @SuppressWarnings("static-access")
    public static String getDateInWeek(Date date) {
        String[] weekDays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int dayIndex = calendar.get(calendar.DAY_OF_WEEK) - calendar.SUNDAY;
        if (dayIndex < 0) {
            dayIndex = 0;
        }
        return weekDays[dayIndex];
    }

    /**
     * 日期减去多少个小时
     * @param date
     * @param hourCount	多少个小时
     * @return
     */
    public static Date getDateReduceHour(Date date, long hourCount) {
        long time = date.getTime() - 3600 * 1000 * hourCount;
        Date dateTemp = new Date();
        dateTemp.setTime(time);
        return dateTemp;
    }

    /**
     * 日期区间分割
     * @param start
     * @param end
     * @param splitCount
     * @return
     */
    public static List<Date> getDateSplit(Date start, Date end, long splitCount) {
        long startTime = start.getTime();
        long endTime = end.getTime();
        long between = endTime - startTime;

        long count = splitCount - 1l;
        long section = between / count;

        List<Date> list = new ArrayList<Date>();
        list.add(start);

        for (long i = 1l; i < count; i++) {
            long time = startTime + section * i;
            Date date = new Date();
            date.setTime(time);
            list.add(date);
        }

        list.add(end);

        return list;
    }

    /**
     * 返回两个日期之间隔了多少天，包含开始、结束时间
     * @param start
     * @param end
     * @return
     */
    public static List<String> getDaySpaceDate(Date start, Date end) {
        Calendar fromCalendar = Calendar.getInstance();
        fromCalendar.setTime(start);
        fromCalendar.set(Calendar.HOUR_OF_DAY, 0);
        fromCalendar.set(Calendar.MINUTE, 0);
        fromCalendar.set(Calendar.SECOND, 0);
        fromCalendar.set(Calendar.MILLISECOND, 0);

        Calendar toCalendar = Calendar.getInstance();
        toCalendar.setTime(end);
        toCalendar.set(Calendar.HOUR_OF_DAY, 0);
        toCalendar.set(Calendar.MINUTE, 0);
        toCalendar.set(Calendar.SECOND, 0);
        toCalendar.set(Calendar.MILLISECOND, 0);

        List<String> dateList = new LinkedList<String>();

        long dayCount = (toCalendar.getTime().getTime() - fromCalendar.getTime().getTime()) / (1000 * 60 * 60 * 24);
        if (dayCount < 0) {
            return dateList;
        }

        dateList.add(format(fromCalendar.getTime(), DEFAULT_DATE_PATTERN));

        for (int i = 0; i < dayCount; i++) {
            fromCalendar.add(Calendar.DATE, 1);// 增加一天
            dateList.add(format(fromCalendar.getTime(), DEFAULT_DATE_PATTERN));
        }

        return dateList;
    }

    /**
     * 获取开始时间
     * @param start
     * @param end
     * @return
     */
    public static Date startDateByDay(Date start, int end) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(start);
        calendar.add(Calendar.DATE, end);// 明天1，昨天-1
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date date = calendar.getTime();
        return date;
    }

    /**
     * 获取结束时间
     * @param start
     * @param end
     * @return
     */
    public static Date endDateByDay(Date start) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(start);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        Date date = calendar.getTime();
        return date;
    }

    /**
     * 获取开始时间
     * @param start
     * @param end
     * @return
     */
    public static Date startDateByHour(Date start, int end) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(start);
        calendar.set(Calendar.MINUTE, end);
        Date date = calendar.getTime();
        return date;
    }

    /**
     * 获取结束时间
     * @param start
     * @param end
     * @return
     */
    public static Date endDateByHour(Date end) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(end);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        Date date = calendar.getTime();
        return date;
    }

    /**
     * 根据年份和周得到周的开始和结束日期
     * @param year
     * @param week
     * @return
     */
    public static Map<String, Date> getStartEndDateByWeek(int year, int week) {
        Calendar weekCalendar = new GregorianCalendar();
        weekCalendar.set(Calendar.YEAR, year);
        weekCalendar.set(Calendar.WEEK_OF_YEAR, week);
        weekCalendar.set(Calendar.DAY_OF_WEEK, weekCalendar.getFirstDayOfWeek());

        Date startDate = weekCalendar.getTime(); // 得到周的开始日期

        weekCalendar.roll(Calendar.DAY_OF_WEEK, 6);
        Date endDate = weekCalendar.getTime(); // 得到周的结束日期

        // 开始日期往前推一天
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(startDate);
        startCalendar.add(Calendar.DATE, 1);// 明天1，昨天-1
        startCalendar.set(Calendar.HOUR_OF_DAY, 0);
        startCalendar.set(Calendar.MINUTE, 0);
        startCalendar.set(Calendar.SECOND, 0);
        startCalendar.set(Calendar.MILLISECOND, 0);
        startDate = startCalendar.getTime();

        // 结束日期往前推一天
        Calendar endCalendar = Calendar.getInstance();
        endCalendar.setTime(endDate);
        endCalendar.add(Calendar.DATE, 1);// 明天1，昨天-1
        endCalendar.set(Calendar.HOUR_OF_DAY, 23);
        endCalendar.set(Calendar.MINUTE, 59);
        endCalendar.set(Calendar.SECOND, 59);
        endCalendar.set(Calendar.MILLISECOND, 999);
        endDate = endCalendar.getTime();

        Map<String, Date> map = new HashMap<String, Date>();
        map.put("start", startDate);
        map.put("end", endDate);
        return map;
    }

    /**
     * 根据日期月份，获取月份的开始和结束日期
     * @param date
     * @return
     */
    public static Map<String, Date> getMonthDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        // 得到前一个月的第一天
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
        Date start = calendar.getTime();

        // 得到前一个月的最后一天
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        Date end = calendar.getTime();

        Map<String, Date> map = new HashMap<String, Date>();
        map.put("start", start);
        map.put("end", end);
        return map;
    }

    /**
     * 获取指定日期
     * @param date
     * @param hour
     * @param minute
     * @param second
     * @param millisecond
     * @return
     */
    public static Date getDate(int date, int hour, int minute, int second, int millisecond) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, date);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        calendar.set(Calendar.MILLISECOND, millisecond);
        return calendar.getTime();
    }

    /**
     * @Title: formatToNaturalDate
     * @Description: 日期字符串YYYYMMDD 格式化为自然语言日期（xxxx年xx月xx日）
     * @param strDate 日期字符串 如：（YYYYMMDD，YYYY-MM-DD，YYYY/MM/DD）
     * @return
     * @author Lord 
     * @date 2018年12月20日 下午2:42:46
     */
    public static String formatToNaturalDate(String strDate) {
        String[] strDateArr = null;

        if (strDate.indexOf("-") > -1) {
            strDateArr = strDate.split("-");
        } else if (strDate.indexOf("/") > -1) {
            strDateArr = strDate.split("/");
        } else {

            String year = strDate.substring(0, 4);
            String month = strDate.substring(4, 6);
            String day = strDate.substring(6, 8);

            return String.format("%s年%s月%s日", year, month, day);
        }

        String year = strDateArr[0];
        String month = strDateArr[1];
        String day = strDateArr[2];

        return String.format("%s年%s月%s日", year, month, day);
    }

    // 判断选择的日期是否是今天
    public static boolean isToday(long time) {
        return isThisTime(time, "yyyy-MM-dd");
    }

    // 判断选择的日期是否是本周
    public static boolean isThisWeek(long time) {
        Calendar calendar = Calendar.getInstance();
        int currentWeek = calendar.get(Calendar.WEEK_OF_YEAR);
        calendar.setTime(new Date(time));
        int paramWeek = calendar.get(Calendar.WEEK_OF_YEAR);
        if (paramWeek == currentWeek) {
            return true;
        }
        return false;
    }

    // 判断选择的日期是否是本月
    public static boolean isThisMonth(long time) {
        return isThisTime(time, "yyyy-MM");
    }

    public static boolean isThisTime(long time, String pattern) {
        Date date = new Date(time);
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        String param = sdf.format(date);// 参数时间
        String now = sdf.format(new Date());// 当前时间
        if (param.equals(now)) {
            return true;
        }
        return false;
    }

}
